# coding: utf-8

import os
import shutil
import wx
import xml.dom.minidom as minixml

class CMaterial:
    def __init__(self):
        self._subMaterialList = []
        self._textureMapList = []
        self._ambient = (1.0, 1.0, 1.0)
        self._diffuse = (1.0, 1.0, 1.0)
        self._specular = (1.0, 1.0, 1.0)
        self._shiness = 0
        self._specularLevel = 0
        self._fileName = ''
        
    def __SearchTextureFile(self, fileName):
        # try output texture directory first
        for root, dirs, files in os.walk(wx.GetApp()._mainFrame._dbbTextureDir.GetValue()):
            for f in files:
                if f.lower() == fileName.lower():
                    return True, os.path.join(root, f)
        
        # try each directory in search list
        listTexDir = wx.GetApp()._mainFrame._listTexSearchDir
        dirCount = listTexDir.GetItemCount()
        for i in xrange(0, dirCount):
            for root, dirs, files in os.walk(listTexDir.GetItemText(i)):
                for f in files:
                    if f == fileName:
                        return False, os.path.join(root, f)
        return False, None
    
    def __CopyTexture(self, fileName, modelName):
        exported, filePath = self.__SearchTextureFile(fileName)
        if not filePath:
            print 'Cannot find texture file[%s]' % fileName
            return ''
        
        if exported:
            return REMOVE_ROOT_PATH(filePath)
        else:
            texDir = wx.GetApp()._mainFrame._dbbTextureDir.GetValue()
            destFile = os.path.join(texDir, modelName, fileName)     
            dirName, fileBase = os.path.split(destFile)       
            try: os.makedirs(dirName)
            except: pass            
            try: shutil.copyfile(filePath, destFile)
            except: print 'copy texture file failed[src: %s, dest: %s]' % (filePath, destFile)
            return REMOVE_ROOT_PATH(destFile)

    def WriteFile(self, modelName):
        if not self._fileName:
            return
        
        print 'Write material file: %s' % self._fileName
        impl = minixml.getDOMImplementation()
        newDoc = impl.createDocument(None, None, None)
        mtlElem = newDoc.createElement('Material')
        newDoc.childNodes.append(mtlElem)
        
        # texture mapping list
        for tm in self._textureMapList:
            fileName, baseName = tm
            tmElem = newDoc.createElement('TextureMapping')
            mtlElem.childNodes.append(tmElem)
            
            pathName = self.__CopyTexture(baseName, modelName)
            
            tmElem.setAttributeNode(newDoc.createAttribute('TextureFile'))
            tmElem.setAttribute('TextureFile', pathName)
            tmElem.setAttributeNode(newDoc.createAttribute('TextureName'))
            tmElem.setAttribute('TextureName', 'texture0')

        # ambient
        ambientElem = newDoc.createElement('Ambient')
        mtlElem.childNodes.append(ambientElem)
        
        ambientElem.setAttributeNode(newDoc.createAttribute('Enable'))
        ambientElem.setAttribute('Enable', '1')
        
        ambientElem.setAttributeNode(newDoc.createAttribute('r'))
        ambientElem.setAttribute('r', str(self._ambient[0]))
        ambientElem.setAttributeNode(newDoc.createAttribute('g'))
        ambientElem.setAttribute('g', str(self._ambient[1]))
        ambientElem.setAttributeNode(newDoc.createAttribute('b'))
        ambientElem.setAttribute('b', str(self._ambient[2]))
        
        # diffuse
        diffuseElem = newDoc.createElement('Diffuse')
        mtlElem.childNodes.append(diffuseElem)
        
        diffuseElem.setAttributeNode(newDoc.createAttribute('Enable'))
        diffuseElem.setAttribute('Enable', '1')
        
        diffuseElem.setAttributeNode(newDoc.createAttribute('r'))
        diffuseElem.setAttribute('r', str(self._diffuse[0]))
        diffuseElem.setAttributeNode(newDoc.createAttribute('g'))
        diffuseElem.setAttribute('g', str(self._diffuse[1]))
        diffuseElem.setAttributeNode(newDoc.createAttribute('b'))
        diffuseElem.setAttribute('b', str(self._diffuse[2]))
                
        # specular
        if self._specularLevel != 0:
            specular = map(lambda n : min(1.0, self._specularLevel * n), self._specular)
            
            specularElem = newDoc.createElement('Specular')
            mtlElem.childNodes.append(specularElem)
            
            specularElem.setAttributeNode(newDoc.createAttribute('Enable'))
            specularElem.setAttribute('Enable', '1')
            
            specularElem.setAttributeNode(newDoc.createAttribute('r'))
            specularElem.setAttribute('r', str(specular[0]))
            specularElem.setAttributeNode(newDoc.createAttribute('g'))
            specularElem.setAttribute('g', str(specular[1]))
            specularElem.setAttributeNode(newDoc.createAttribute('b'))
            specularElem.setAttribute('b', str(specular[2]))

            specularElem.setAttributeNode(newDoc.createAttribute('Shiness'))
            specularElem.setAttribute('Shiness', str(self._shiness))
        
        pathName = os.path.join(wx.GetApp()._mainFrame._dbbMtlDir.GetValue(), modelName)
        fileName = os.path.join(pathName, self._fileName)
                
        try: os.makedirs(pathName)
        except: pass
        newDoc.writexml(open(fileName, 'w'),    newl = '\r\n', addindent = '    ', encoding = 'utf-8')
        newDoc.unlink() 
        
class CMaterialExport:
    """
        Only parse one sub material level.
    """
    def __init__(self):
        self._materialList = []
        self._modelName = ''
    
    def DoExport(self, xmlDoc, modelName):
        self._materialList = []
        self._modelName = modelName
                
        print 'Export material'
        for igameNode in xmlDoc.childNodes:
            if igameNode.nodeName == 'IGame':
                for mtlListNode in igameNode.childNodes:
                    if mtlListNode.nodeName == 'MaterialList':
                        for mtlNode in mtlListNode.childNodes:
                            if mtlNode.nodeName == 'Material':
                                # multi-material
                                if mtlNode.getAttribute('Class') == 'Multi/Sub-Object':
                                    mtl = self.ParseMultiMaterial(mtlNode)
                                    self._materialList.append(mtl)
                                # single-material
                                elif mtlNode.getAttribute('Class') == 'Standard':
                                    mtl = self.ParseMaterial(mtlNode)
                                    self._materialList.append(mtl)
                                    
    def ParseMultiMaterial(self, mtlNode):
        mtl = CMaterial()
        for node in mtlNode.childNodes:
            if node.nodeName == 'MultiMaterial':
                for subMtlNode in node.childNodes:
                    if subMtlNode.nodeName == 'Material':
                        subMtl = self.ParseMaterial(subMtlNode)
                        mtl._subMaterialList.append(subMtl)
        return mtl
                                
    def ParseMaterial(self, mtlNode):
        mtl = CMaterial()
        mtl._fileName = '%s.mtl.xml' % mtlNode.getAttribute('Name')
        for node in mtlNode.childNodes:
            if node.nodeName == 'Properties':
                self.ParseProperties(node, mtl)
            elif node.nodeName == 'TextureMaps':
                self.ParseTextureMaps(node, mtl)
                
        return mtl
                
    def ParseProperties(self, node, mtl):
        for propNode in node.childNodes:
            if propNode.nodeName == 'Prop':
                if propNode.getAttribute('name') == 'ambient':
                    value = propNode.getAttribute('Value')
                    mtl._ambient = map(float, value.strip().split(' '))
                elif propNode.getAttribute('name') == 'diffuse':
                    value = propNode.getAttribute('Value')
                    mtl._diffuse = map(float, value.strip().split(' '))
                elif propNode.getAttribute('name') == 'specular':
                    value = propNode.getAttribute('Value')
                    mtl._specular = map(float, value.strip().split(' '))
                elif propNode.getAttribute('name') == 'glossiness':
                    value = propNode.getAttribute('Value')
                    mtl._shiness = float(value)
                elif propNode.getAttribute('name') == 'specularLevel':
                    value = propNode.getAttribute('Value')
                    mtl._specularLevel = float(value)
                    
    def ParseTextureMaps(self, node, mtl):
        for texNode in node.childNodes:
            if texNode.nodeName == 'Texture' and texNode.getAttribute('Slot') == 'Diffuse':
                for bmpNode in texNode.childNodes:
                    if bmpNode.nodeName == 'BitmapTexture':
                        fileName = bmpNode.getAttribute('Filename')
                        if len(fileName) >1 and fileName[1] == '$':
                            fileName = fileName.replace('$', ':', 1)
                        dirName, fileBase = os.path.split(fileName)
                        mtl._textureMapList.append((fileName, fileBase))
                        
    def WriteFile(self, meshExportList):
        mtlIndexList = []
        for meshExport in meshExportList:
            for subMesh in meshExport._subMeshList:
                mtlItem = (subMesh._materialIndex, subMesh._subMaterialIndex)
                if mtlItem in mtlIndexList:
                    continue
                mtlIndexList.append(mtlItem)
                mtl = self._materialList[subMesh._materialIndex]
                if mtl._subMaterialList:
                    mtl = mtl._subMaterialList[subMesh._subMaterialIndex]
                mtl.WriteFile(self._modelName)
                
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    